package com.Unidbg_hengdin.Mysyscall;

import com.alibaba.fastjson.util.IOUtils;
import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.Emulator;
import com.github.unidbg.Module;
import com.github.unidbg.arm.backend.Unicorn2Factory;
import com.github.unidbg.arm.context.RegisterContext;
import com.github.unidbg.debugger.BreakPointCallback;
import com.github.unidbg.file.FileResult;
import com.github.unidbg.file.IOResolver;
import com.github.unidbg.file.linux.AndroidFileIO;
import com.github.unidbg.linux.ARM64SyscallHandler;
import com.github.unidbg.linux.android.AndroidARM64Emulator;
import com.github.unidbg.linux.android.AndroidARMEmulator;
import com.github.unidbg.linux.android.AndroidEmulatorBuilder;
import com.github.unidbg.linux.android.AndroidResolver;
import com.github.unidbg.linux.android.dvm.*;
import com.github.unidbg.linux.file.SimpleFileIO;
import com.github.unidbg.memory.Memory;
import com.github.unidbg.memory.SvcMemory;
import com.github.unidbg.unix.UnixSyscallHandler;
import unicorn.Arm64Const;

import java.io.File;


public class xiaojianbangFile extends AbstractJni implements IOResolver {
    private final AndroidEmulator emulator;
    private final VM vm;
    private final Module module;

    private final DvmClass NativeHelperUtils;

    private final boolean logging;

    private int count = 0;
    xiaojianbangFile(boolean logging) {
        this.logging = logging;
//
//        emulator = AndroidEmulatorBuilder.for64Bit()
//                .setProcessName("com.xiaojianbang.app")
//                .addBackendFactory(new Unicorn2Factory(true))
//                .setRootDir(new File("unidbg-android\\src\\test\\java\\com\\xiaojianbang\\filehandle\\rootfs")).build(); // 创建模拟器实例，要模拟32位或者64位，在这里区分

        // 创建匿名的类，目的是为了调用自写的 MySyscallHandler
        AndroidEmulatorBuilder bulider = new AndroidEmulatorBuilder(true){
            public AndroidEmulator bulid(){
                return new AndroidARM64Emulator(processName, rootDir, backendFactories) {
                    @Override
                    protected UnixSyscallHandler<AndroidFileIO> createSyscallHandler(SvcMemory svcMemory) {
                        // 最终目的是修改 此处的 SyscallHandler 为自写的 MySyscallHandler
                        return new MySyscallHandler(svcMemory);
                    }
                };
            }
        };

        // 创建新的 emulator
        emulator = bulider.setProcessName("com.xiaojianbang.app")
                .setRootDir(new File("unidbg-android\\src\\test\\java\\com\\Unidbg_hengdin\\Mysyscall\\rootfs"))
                .addBackendFactory(new Unicorn2Factory(true))
                .build();



        final Memory memory = emulator.getMemory(); // 模拟器的内存操作接口
        memory.setLibraryResolver(new AndroidResolver(23)); // 设置系统类库解析
        // IOResolver 的注册
//        emulator.getSyscallHandler().addIOResolver(this);
        //
        System.out.println(emulator.getFileSystem().getRootDir()); // 设置前：C:\Users\ADMINI~1\AppData\Local\Temp\rootfs\default 设置后：unidbg-android\src\test\java\com\xiaojianbang\filehandle\rootfs


        vm = emulator.createDalvikVM(); // 创建Android虚拟机
        vm.setVerbose(logging); // 设置是否打印Jni调用细节      unidbg-android/src/test/java/com/Unidbg_hengdin/ndk/libxiaojianbang.so
        vm.setJni(this);
        DalvikModule dm = vm.loadLibrary(new File("unidbg-android/src/test/java/com/Unidbg_hengdin/Mysyscall/libxiaojianbang_popen.so"), false); // 加载libttEncrypt.so到unicorn虚拟内存，加载成功以后会默认调用init_array等函数
//        dm.callJNI_OnLoad(emulator); // 手动执行JNI_OnLoad函数
        module = dm.getModule(); // 加载好的libttEncrypt.so对应为一个模块

        NativeHelperUtils = vm.resolveClass("com/xiaojianbang/ndk/NativeHelper");


        int pid = emulator.getPid();
        System.out.println("current pid: " + pid);

        emulator.set("author_2025","hengdin");



    }

    void destroy() {
        IOUtils.close(emulator);
        if (logging) {
            System.out.println("destroy");
        }
    }

    public static void main(String[] args) throws Exception {
        xiaojianbangFile test = new xiaojianbangFile(true);

//        int data = test.callFun();
        test.callFun();

//        Inspector.inspect(data, "callFun");
//

        test.destroy();
    }

    void callFun() {

//        byte[] data = new byte[16];

//        调用 add 方法
//        int retval = NativeHelperUtils.callStaticJniMethodInt(emulator, "add(III)I", 0x100, 0x200, 0x300); // 执行Jni方法
//        System.out.println("res : 0x" + Integer.toHexString(retval));

//        调用MD5方法
//        StringObject md5_retval = NativeHelperUtils.callStaticJniMethodObject(emulator, "md5(Ljava/lang/String;)Ljava/lang/String;", new StringObject(vm,"123456")); // 执行Jni方法
//        System.out.println("md5_retval res : " + md5_retval.getValue());
        // 测试 emulator.get
        String my_flag = emulator.get("author_2025");
        System.out.println("author_2025 :" + my_flag);
        // 通过libc里的setenv设置环境变量
//        Symbol setenv = module.findSymbolByName("setenv");
//        setenv.call(emulator,"PATH","xxx666",0);


        // hook getenv
        emulator.attach().addBreakPoint(module.findSymbolByName("getenv").getAddress(), new BreakPointCallback() {
            @Override
            public boolean onHit(Emulator<?> emulator, long address) {
                RegisterContext context = emulator.getContext();
                String res = context.getPointerArg(0).getString(0);
                System.out.println("getenv args " + res);
                return true;
            }
        });
        // hook popen
        emulator.attach().addBreakPoint(module.findSymbolByName("popen").getAddress(), new BreakPointCallback() {
            @Override
            public boolean onHit(Emulator<?> emulator, long address) {
                RegisterContext context = emulator.getContext();
                String commad = context.getPointerArg(0).getString(0);
                System.out.println("popen args " + commad);
                return true;
            }
        });
        // 跳过 popen 的执行16B0
//        emulator.attach().addBreakPoint(module.base + 0x26E4, new BreakPointCallback() {
//            @Override
//            public boolean onHit(Emulator<?> emulator, long address) {
//                emulator.getBackend().reg_write(Arm64Const.UC_ARM64_REG_PC,address+4); // 跳过这个函数的调用
//                return true;
//            }
//        });
        //  __fgets_chk 的跳过
//        emulator.attach().addBreakPoint(module.base + 0x2744, new BreakPointCallback() {
//            @Override
//            public boolean onHit(Emulator<?> emulator, long address) {
////
//                emulator.getBackend().reg_write(Arm64Const.UC_ARM64_REG_PC,address+4); // 跳过这个函数的调用
//                return true;
//            }
//        });

//        emulator.attach().addBreakPoint(module.base + 0x276C);
        // 实现 只调用一次循环体的内容
//        emulator.attach().addBreakPoint(module.base + 0x276C, new BreakPointCallback() {
//            @Override
//            public boolean onHit(Emulator<?> emulator, long address) {
//                if(count ==0){
//                    count += 1 ;
//                    System.out.println("0x276C : 1" );
//                }else if (count != 0) {
//                    emulator.getBackend().reg_write(Arm64Const.UC_ARM64_REG_X8, 0); // 跳过这个函数的调用
////                    emulator.getBackend().reg_write(Arm64Const.UC_ARM64_REG_X8,1); // 修改r0的值
//                }
//                return true;
//            }
//        });

//        调用encode 方法
        StringObject encodeRetval = NativeHelperUtils.callStaticJniMethodObject(emulator, "readSomething()"); // 执行Jni方法
        System.out.println("fileRead res : " + encodeRetval.getValue());

    }



    @Override
    public FileResult resolve(Emulator emulator, String pathname, int oflags) {
        System.out.println("pathname --------------------------------：" + pathname);
        if ("/proc/self/maps".equals(pathname)){
                    return FileResult.success(new SimpleFileIO(oflags, new File("F:\\unidbg-master\\unidbg-android\\src\\test\\java\\com\\Unidbg_hengdin\\filehandle\\maps"), pathname));
//            return FileResult.success(new ByteArrayFileIO(oflags, pathname, "hengdin test filehandler".getBytes()));
        }


        return null;
    }
}